Allow `command` to be an array of arguments in ShellCommandAgent

With this, you can safely pass a string contained in an incoming event
as an argument to a command without worrying about meta-characters.

Akinori MUSHA 9 years ago
parent
commit
d9d5fbf824
2 changed files with 30 additions and 7 deletions
  1. 6 2
      app/models/agents/shell_command_agent.rb
  2. 24 5
      spec/models/agents/shell_command_agent_spec.rb

+ 6 - 2
app/models/agents/shell_command_agent.rb

@@ -11,7 +11,7 @@ module Agents
11 11
     description <<-MD
12 12
       The Shell Command Agent will execute commands on your local system, returning the output.
13 13
 
14
-      `command` specifies the command to be executed, and `path` will tell ShellCommandAgent in what directory to run this command.
14
+      `command` specifies the command (either a shell command line string or an array of command line arguments) to be executed, and `path` will tell ShellCommandAgent in what directory to run this command.
15 15
 
16 16
       `expected_update_period_in_days` is used to determine if the Agent is working.
17 17
 
@@ -50,6 +50,10 @@ module Agents
50 50
         errors.add(:base, "The path, command, and expected_update_period_in_days fields are all required.")
51 51
       end
52 52
 
53
+      unless Array(options['command']).all? { |o| o.is_a?(String) }
54
+        errors.add(:base, "command must be a shell command line string or an array of command line arguments.")
55
+      end
56
+
53 57
       unless File.directory?(options['path'])
54 58
         errors.add(:base, "#{options['path']} is not a real directory.")
55 59
       end
@@ -92,7 +96,7 @@ module Agents
92 96
         rout, wout = IO.pipe
93 97
         rerr, werr = IO.pipe
94 98
 
95
-        pid = spawn(command, chdir: path, out: wout, err: werr)
99
+        pid = spawn(*command, chdir: path, out: wout, err: werr)
96 100
 
97 101
         wout.close
98 102
         werr.close

+ 24 - 5
spec/models/agents/shell_command_agent_spec.rb

@@ -5,15 +5,25 @@ describe Agents::ShellCommandAgent do
5 5
     @valid_path = Dir.pwd
6 6
 
7 7
     @valid_params = {
8
-        :path  => @valid_path,
9
-        :command  => "pwd",
10
-        :expected_update_period_in_days => "1",
11
-      }
8
+      path: @valid_path,
9
+      command: 'pwd',
10
+      expected_update_period_in_days: '1',
11
+    }
12
+
13
+    @valid_params2 = {
14
+      path: @valid_path,
15
+      command: [RbConfig.ruby, '-e', 'puts "hello, world."; STDERR.puts "warning!"'],
16
+      expected_update_period_in_days: '1',
17
+    }
12 18
 
13
-    @checker = Agents::ShellCommandAgent.new(:name => "somename", :options => @valid_params)
19
+    @checker = Agents::ShellCommandAgent.new(name: 'somename', options: @valid_params)
14 20
     @checker.user = users(:jane)
15 21
     @checker.save!
16 22
 
23
+    @checker2 = Agents::ShellCommandAgent.new(name: 'somename2', options: @valid_params2)
24
+    @checker2.user = users(:jane)
25
+    @checker2.save!
26
+
17 27
     @event = Event.new
18 28
     @event.agent = agents(:jane_weather_agent)
19 29
     @event.payload = {
@@ -27,6 +37,7 @@ describe Agents::ShellCommandAgent do
27 37
   describe "validation" do
28 38
     before do
29 39
       expect(@checker).to be_valid
40
+      expect(@checker2).to be_valid
30 41
     end
31 42
 
32 43
     it "should validate presence of necessary fields" do
@@ -70,6 +81,14 @@ describe Agents::ShellCommandAgent do
70 81
       expect(Event.last.payload[:output]).to eq("fake pwd output")
71 82
     end
72 83
 
84
+    it "should create an event when checking (unstubbed)" do
85
+      expect { @checker2.check }.to change { Event.count }.by(1)
86
+      expect(Event.last.payload[:path]).to eq(@valid_path)
87
+      expect(Event.last.payload[:command]).to eq([RbConfig.ruby, '-e', 'puts "hello, world."; STDERR.puts "warning!"'])
88
+      expect(Event.last.payload[:output]).to eq('hello, world.')
89
+      expect(Event.last.payload[:errors]).to eq('warning!')
90
+    end
91
+
73 92
     it "does not run when should_run? is false" do
74 93
       stub(Agents::ShellCommandAgent).should_run? { false }
75 94
       expect { @checker.check }.not_to change { Event.count }